package com.yeyks.commonReference.service.order.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.yeyks.cnbooking.Result.booking.CbBookingData;
import com.yeyks.cnbooking.Result.prebookingcheck.CbPreBookingCheckData;
import com.yeyks.cnbooking.base.CNResponse;
import com.yeyks.cnbooking.param.CbPreBookingCheckParam;
import com.yeyks.cnbooking.param.booking.CbBookInfo;
import com.yeyks.cnbooking.param.booking.CbBookingParam;
import com.yeyks.cnbooking.param.booking.CbGuestInfo;
import com.yeyks.cnbooking.param.booking.CbOrder;
import com.yeyks.cnbooking.service.CNBookingService;
import com.yeyks.common.ajax.AjaxResponseBody;
import com.yeyks.common.constants.MessageTemplate;
import com.yeyks.common.constants.OrderHeadExtraInfoConstant;
import com.yeyks.common.constants.OrderStatus;
import com.yeyks.common.constants.cnbooking.CnBookingStaticConstant;
import com.yeyks.common.constants.hotel.HotelSourceType;
import com.yeyks.common.dto.mq.GrabTheOrderSuccessMessage;
import com.yeyks.common.em.OrderStatusEnum;
import com.yeyks.common.em.UserCouponInfoStatus;
import com.yeyks.common.em.order.OrderVipFlagEnum;
import com.yeyks.common.em.pay.PayTypeEnum;
import com.yeyks.common.em.vip.VipCardTypeEnum;
import com.yeyks.common.exception.ServiceException;
import com.yeyks.common.utils.DateUtils;
import com.yeyks.common.utils.FormatUtils;
import com.yeyks.commonReference.append.getui.service.AppServerGeTuiService;
import com.yeyks.commonReference.append.pay.PayService;
import com.yeyks.commonReference.append.rocketmq.service.producer.MQProducerService;
import com.yeyks.commonReference.append.sms.SmsService;
import com.yeyks.commonReference.service.calendar.RoomCalendarJipInfoService;
import com.yeyks.commonReference.service.consumer.MessageNoticeTemplateService;
import com.yeyks.commonReference.service.consumer.UserCouponInfoService;
import com.yeyks.commonReference.service.hotel.HotelInfoService;
import com.yeyks.commonReference.service.hotel.RoomInfoService;
import com.yeyks.commonReference.service.order.OrderHeadService;
import com.yeyks.commonReference.service.order.OrderPayRecordService;
import com.yeyks.commonReference.utils.UserUtils;
import com.yeyks.consumer.dal.domain.MemberCardDetail;
import com.yeyks.consumer.dal.domain.UserCouponInfo;
import com.yeyks.consumer.dal.domain.UserInfo;
import com.yeyks.consumer.dal.domain.UserMemberCard;
import com.yeyks.consumer.service.MemberCardDetailService;
import com.yeyks.consumer.service.MessageNoticeService;
import com.yeyks.consumer.service.UserInfoService;
import com.yeyks.commonReference.service.consumer.UserMemberCardService;
import com.yeyks.hotel.dal.domain.*;
import com.yeyks.hotel.service.RoomCalendarInfoService;
import com.yeyks.hotel.service.RoomCalendarVipInfoService;
import com.yeyks.order.dal.dao.OrderPayRecordMapper;
import com.yeyks.order.dal.domain.OrderHead;
import com.yeyks.order.dal.domain.OrderPayRecord;
import com.yeyks.order.param.OrderPayRecordC2bCreateOrderPayRecordParam;
import com.yeyks.search.constants.EsIndexConstant;
import com.yeyks.search.pojo.model.EsHotelInfo;
import com.yeyks.search.pojo.model.EsRoomCalendarInfo;
import com.yeyks.search.pojo.model.EsRoomInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <p>
 * 订单支付记录表 服务实现类
 * </p>
 *
 * @author yun
 * @since 2019-06-25
 */
@Slf4j
@Service
public class OrderPayRecordServiceImpl extends ServiceImpl<OrderPayRecordMapper, OrderPayRecord> implements OrderPayRecordService {


    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    private CNBookingService cnBookingService;


    @Autowired
    private MQProducerService mqProducerService;
    @Autowired
    private OrderPayRecordService orderPayRecordService;
    @Autowired
    private OrderHeadService orderHeadService;
    @Autowired
    private OrderPayRecordMapper orderPayRecordMapper;
    @Autowired
    private RoomCalendarInfoService roomCalendarInfoService;
    @Autowired
    private RoomCalendarVipInfoService roomCalendarVipInfoService;
    @Autowired
    private RoomCalendarJipInfoService roomCalendarJipInfoService;
    @Autowired
    private UserMemberCardService userMemberCardService;
    @Autowired
    private PayService payService;
    @Autowired
    private UserCouponInfoService userCouponInfoService;
    @Autowired
    private SmsService smsService;
    @Autowired
    private HotelInfoService hotelInfoService;
    @Autowired
    private RoomInfoService roomInfoService;
    @Autowired
    private MessageNoticeTemplateService messageNoticeTemplateService;
    @Autowired
    private MessageNoticeService messageNoticeService;
    @Autowired(required = false)
    private AppServerGeTuiService geTuiService;
    @Autowired
    private MemberCardDetailService memberCardDetailService;
    @Autowired
    private UserInfoService userInfoService;

    private static final List<Integer> vipFlagNew = CollectionUtil.newArrayList(0);

    /**
     * 通过订单号查询支付对象
     *
     * @param orderNo
     * @return
     */
    @Override
    public OrderPayRecord selectOrderNo(String orderNo) {
        return baseMapper.selectOrderNo(orderNo);

    }

    /**
     * 根据回调结果更新支付信息
     *
     * @param orderPayRecord
     * @return
     */
    @Override
    public Integer update(OrderPayRecord orderPayRecord) {
        orderPayRecord.setUpdateTime(new Date());
        return baseMapper.updateById(orderPayRecord);
    }

    //:v3.3
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResponseBody<Map<String, Object>> c2bCreateOrderPayRecord(OrderPayRecordC2bCreateOrderPayRecordParam param) {
        return c2bCreateOrderPayRecord(param.getOrderNo(), param.getPayTypeInt(), param.getWxOpenId(), param.getPayPassword(), param.getIp());
    }

    public AjaxResponseBody<Map<String, Object>> c2bCreateOrderPayRecord(String orderNo, Integer payTypeInt, String wxOpenId, String payPassword, String ip) {
        String payTypeDesc = PayTypeEnum.getDesc(payTypeInt);
        UserInfo loginUser = UserUtils.getLoginUser();
        //查询订单
        OrderHead orderHead = orderHeadService.getOne(new QueryWrapper<OrderHead>()
                .eq(OrderHead.ORDER_NO, orderNo).eq(OrderHead.USER_ID, loginUser.getId()));
        if (null == orderHead) {
            throw new ServiceException("订单不存在");
        }
        if (!CollectionUtil.list(false, OrderStatus.prePay).contains(orderHead.getStatus())) {
            throw new ServiceException("订单状态不正确");
        }
        //查询订单记录是否已支付
        OrderPayRecord orderPayRecordPaid = baseMapper.selectOne(new QueryWrapper<OrderPayRecord>()
                .eq(OrderPayRecord.ORDER_NO, orderNo).eq(OrderPayRecord.STATUS, "付款成功"));
        if (null != orderPayRecordPaid) {
            throw new ServiceException("订单已支付");
        }
        //cn下单校验
        if (Objects.equals(orderHead.getSourceType(), HotelSourceType.CN)) {
            CbPreBookingCheckParam cbPreBookingCheckParam = new CbPreBookingCheckParam();
            cbPreBookingCheckParam.setHotelId(orderHead.getSourceHotelId());
            cbPreBookingCheckParam.setRoomId(orderHead.getSourceRoomId());
            cbPreBookingCheckParam.setRateplanId(orderHead.getRateplanId());
            cbPreBookingCheckParam.setCheckIn(DatePattern.NORM_DATE_FORMAT.format(orderHead.getCheckIn()));
            cbPreBookingCheckParam.setCheckOut(DatePattern.NORM_DATE_FORMAT.format(orderHead.getCheckOut()));
            cbPreBookingCheckParam.setRoomCount(String.valueOf(orderHead.getRoomCount()));
            cbPreBookingCheckParam.setCurrency(CnBookingStaticConstant.RMB);
            cbPreBookingCheckParam.setOrderAmount(String.valueOf(orderHead.getSourceAmount() / 100));
            log.info("支付前cn下单校验请求参数记录,-----{}", cbPreBookingCheckParam);
            CNResponse<CbPreBookingCheckData> cbPreBookingCheckDataCNResponse = cnBookingService.preBookingCheck(cbPreBookingCheckParam);
            log.info("支付前cn下单校验返回记录,-----{}------{}", orderHead.getOrderNo(), JSONUtil.toJsonStr(cbPreBookingCheckDataCNResponse));
            if (!Objects.equals(cbPreBookingCheckDataCNResponse.getMessageInfo().getCode(), CnBookingStaticConstant.CODE_SUCCESS)
                    || !Objects.equals(cbPreBookingCheckDataCNResponse.getData().getReturnCode(), CnBookingStaticConstant.CODE_SUCCESS_SCHEDULED_VERIFICATION_PASS)) {
                throw new ServiceException("房源已被抢订,请重新选择");
            }
        }
        //获取微信信息
        Map<String, Object> payResultMap = payService.orderHeadPay(payTypeDesc, orderNo, wxOpenId, payPassword, ip);
        //查询订单记录是否已经生成
        OrderPayRecord orderPayRecordUnpaid = baseMapper.selectOne(new QueryWrapper<OrderPayRecord>()
                .eq(OrderPayRecord.ORDER_NO, orderNo).eq(OrderPayRecord.PAY_TYPE, payTypeDesc).isNull(OrderPayRecord.STATUS));
        //订单未生成
        if (null == orderPayRecordUnpaid) {
            OrderPayRecord orderPayRecord = new OrderPayRecord();
            orderPayRecord.setOrderNo(orderNo);
            orderPayRecord.setPayType(payTypeDesc);
            orderPayRecord.setStartTime(new Date());
            orderPayRecord.setAmount(orderHead.getSnapshotTotalFee());
            orderPayRecord.setPayAccount(loginUser.getPhone());
            orderPayRecord.setUserAccount(loginUser.getName());
            orderPayRecord.setCreateTime(new Date());
            orderPayRecord.setUpdateTime(new Date());
            int insert = orderPayRecordMapper.insert(orderPayRecord);
            if (insert < 1) {
                throw new ServiceException("支付记录生成失败");
            }
        }
        return AjaxResponseBody.success(payResultMap);
    }

    //订单支付回调处理:v3.3
    @Override
    public void payCallback(String orderNo, PayTypeEnum payTypeEnum, Boolean succeeded) {
        try {
//            ((OrderPayRecordService)AopContext.currentProxy()).payCallBackT(orderNo, payTypeEnum, succeeded);
            orderPayRecordService.payCallBackT(orderNo, payTypeEnum, succeeded);
        } catch (Exception e) {
            log.error("订单回调处理失败,orderNo:{},payAttach:{},succeeded:{},e:{}", orderNo, payTypeEnum, succeeded, e.getMessage());
        }
    }

    //订单支付回调处理,事务包裹:v3.3
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void payCallBackT(String orderNo, PayTypeEnum payTypeEnum, Boolean succeeded) {
        OrderHead orderHead = orderHeadService.getByOrderNo(orderNo);
        if (CollectionUtil.contains(vipFlagNew, orderHead.getVipFlag())) {
            //综合回调
            payCallBackTAfter(orderHead, orderNo, payTypeEnum, succeeded);
        } else {
            //老回调
            payCallBackTBefore(orderHead, orderNo, payTypeEnum, succeeded);
        }
    }

    //订单支付回调处理,事务包裹:v3.6 综合回调综合回调
    @Transactional(rollbackFor = Exception.class)
    public void payCallBackTAfter(OrderHead orderHead, String orderNo, PayTypeEnum payTypeEnum, Boolean succeeded) {
        Integer cardType = VipCardTypeEnum.getCardTypeByOrderVipFlagValue(orderHead.getVipFlag());
        //判断是否是待支付订单
        if (OrderStatusEnum.PREPAY.value().equals(orderHead.getStatus())) {
            try {


                //获取用户信息
                UserInfo userInfo = userInfoService.getById(orderHead.getUserId());


                //房间 酒店 房态信息
                //
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                        //房间
                        .must(
                                QueryBuilders.boolQuery()
                                        .must(
                                                QueryBuilders.termQuery("sourceType", orderHead.getSourceType())
                                        )
                                        .must(
                                                QueryBuilders.termQuery("sourceId", orderHead.getSourceRoomId())
                                        )
                        )
                        //酒店
                        .must(
                                JoinQueryBuilders.hasParentQuery(
                                        EsIndexConstant.JOIN_TYPE_HOTEL,
                                        QueryBuilders.matchAllQuery(),
                                        false
                                ).innerHit(new InnerHitBuilder().setSize(100))
                        )
                        //房态
                        .must(
                                JoinQueryBuilders.hasChildQuery(
                                        EsIndexConstant.JOIN_TYPE_CALENDAR,
                                        QueryBuilders.rangeQuery("date")
                                                .gte(orderHead.getCheckIn())
                                                .lt(orderHead.getCheckOut())
                                        ,
                                        ScoreMode.None
                                ).innerHit(new InnerHitBuilder().setSize(100))
                        );
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                searchSourceBuilder.size(10);
                searchSourceBuilder.query(boolQueryBuilder);
                //
                SearchRequest searchRequest = new SearchRequest(EsIndexConstant.INDEX_HOTEL);
                searchRequest.types(EsIndexConstant.NORMAL_TYPE);
                searchRequest.source(searchSourceBuilder);
                SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                //转换数据
                //房间
                if (searchResponse.getHits().getTotalHits() != 1) {
                    throw new ServiceException("房间信息不存在");
                }
                SearchHit searchHitRoom = searchResponse.getHits().getHits()[0];
                EsRoomInfo esRoomInfo = JSONUtil.toBean(searchHitRoom.getSourceAsString(), EsRoomInfo.class);
                //酒店
                if (searchHitRoom.getInnerHits().get(EsIndexConstant.JOIN_TYPE_HOTEL).getTotalHits() != 1) {
                    throw new ServiceException("酒店信息不存在");
                }
                EsHotelInfo esHotelInfo = JSONUtil.toBean(searchHitRoom.getInnerHits().get(EsIndexConstant.JOIN_TYPE_HOTEL).getHits()[0].getSourceAsString(), EsHotelInfo.class);
                //房态
                if (searchHitRoom.getInnerHits().get(EsIndexConstant.JOIN_TYPE_CALENDAR).getTotalHits() < 1) {
                    throw new ServiceException("房态信息不存在");
                }
                SearchHit[] searchHitCalendars = searchHitRoom.getInnerHits().get(EsIndexConstant.JOIN_TYPE_CALENDAR).getHits();
                ArrayList<EsRoomCalendarInfo> esRoomCalendarInfos = new ArrayList<>();
                for (SearchHit searchHitCalendar : searchHitCalendars) {
                    esRoomCalendarInfos.add(JSONUtil.toBean(searchHitCalendar.getSourceAsString(), EsRoomCalendarInfo.class));
                }


                //更新订单信息
                OrderHead orderHeadNew = new OrderHead();
                orderHeadNew.setId(orderHead.getId());
                orderHeadNew.setGmtModified(new Date());
                if (succeeded) {
                    //住店那天18点后的订单直接改为入住中
                    if (new Date().after(DateUtil.beginOfDay(orderHead.getCheckIn()).offset(DateField.HOUR, 18))) {
                        orderHeadNew.setStatus(OrderStatusEnum.LIVING.value());
                    } else {
                        orderHeadNew.setStatus(OrderStatusEnum.PRECHECKIN.value());
                    }
                } else {
                    orderHeadNew.setStatus(OrderStatusEnum.PAYFAILED.value());
                }
                orderHeadNew.setPaymentMethod(payTypeEnum.value());
                boolean b = orderHeadService.updateById(orderHeadNew);
                if (!b) {
                    throw new ServiceException("订单更新失败");
                }


                //更新房态信息 或下单
                switch (orderHead.getSourceType()) {
                    case HotelSourceType.CN:
                        //cn下单校验
                        CbPreBookingCheckParam cbPreBookingCheckParam = new CbPreBookingCheckParam();
                        cbPreBookingCheckParam.setHotelId(esHotelInfo.getSourceId());
                        cbPreBookingCheckParam.setRoomId(esRoomInfo.getSourceId());
                        cbPreBookingCheckParam.setRateplanId(esRoomCalendarInfos.get(0).getRatePlanId());
                        cbPreBookingCheckParam.setCheckIn(DatePattern.NORM_DATE_FORMAT.format(orderHead.getCheckIn()));
                        cbPreBookingCheckParam.setCheckOut(DatePattern.NORM_DATE_FORMAT.format(orderHead.getCheckOut()));
                        cbPreBookingCheckParam.setRoomCount(String.valueOf(orderHead.getRoomCount()));
                        cbPreBookingCheckParam.setCurrency(CnBookingStaticConstant.RMB);
                        cbPreBookingCheckParam.setOrderAmount(String.valueOf(orderHead.getSourceAmount() / 100));
                        log.info("回调cn下单校验请求参数记录,-----{}", cbPreBookingCheckParam);
                        CNResponse<CbPreBookingCheckData> cbPreBookingCheckDataCNResponse = cnBookingService.preBookingCheck(cbPreBookingCheckParam);
                        log.info("回调cn下单校验返回记录,-----{}------{}", orderHead.getOrderNo(), JSONUtil.toJsonStr(cbPreBookingCheckDataCNResponse));
                        //cn下单
                        CbBookingParam cbBookingParam = new CbBookingParam();
                        cbBookingParam.setHotelId(orderHead.getSourceHotelId());
                        cbBookingParam.setRoomId(orderHead.getSourceRoomId());
                        cbBookingParam.setRateplanId(esRoomCalendarInfos.get(0).getRatePlanId());
                        cbBookingParam.setCheckIn(DatePattern.NORM_DATE_FORMAT.format(orderHead.getCheckIn()));
                        cbBookingParam.setCheckOut(DatePattern.NORM_DATE_FORMAT.format(orderHead.getCheckOut()));
                        cbBookingParam.setRoomCount(orderHead.getRoomCount());
                        cbBookingParam.setCurrency(CnBookingStaticConstant.RMB);
                        cbBookingParam.setOrderAmount(String.valueOf(orderHead.getSourceAmount() / 100));
                        cbBookingParam.setBookInfo(new CbBookInfo().setBookName(StrUtil.isNotBlank(userInfo.getName()) ? userInfo.getName() : "佚名").setBookPhone(userInfo.getPhone()));
                        cbBookingParam.setGuestInfo(new CbGuestInfo().setGuestName(orderHead.getContactName()).setGuestPhone(orderHead.getContactPhone()));
//                        cbBookingParam.setReserve();
//                        cbBookingParam.setSpecialRemark();
                        cbBookingParam.setCustomerOrderId(orderHead.getOrderNo());
                        log.info("cn下单请求参数记录,-----{}", cbBookingParam);
                        CNResponse<CbBookingData> booking = cnBookingService.booking(cbBookingParam);
                        log.info("cn下单返回记录,-----{}------{}", orderHead.getOrderNo(), JSONUtil.toJsonStr(booking));
                        if (Objects.equals(booking.getMessageInfo().getCode(), CnBookingStaticConstant.CODE_SUCCESS)
                                && Objects.equals(booking.getData().getReturnCode(), CnBookingStaticConstant.CODE_BOOKING_SUCCESS)) {
                            CbOrder cbOrder = booking.getData().getOrder();
                            //存储订单信息
                            boolean update = orderHeadService.update(
                                    new UpdateWrapper<OrderHead>()
                                            .set(OrderHead.STATUS, OrderStatusEnum.toBeConfirmed.value())
                                            .set(OrderHead.SOURCE_ORDER_ID, cbOrder.getOrderId())
                                            .set(OrderHead.LAST_CANCEL_TIME, cbOrder.getLastCancelTime())
                                            .eq(OrderHead.ID, orderHead.getId())
                            );
                        } else {
                            //退款
                            orderHeadService.cancelOrderNoCheck(orderNo, "预订订单失败,订单取消");
                            return;
                        }
                        break;
                    case HotelSourceType.YYKS:
                        //更新房态
                        switch (orderHead.getVipFlag()) {
                            //c2b 和 3.4订单
                            case 0:
                                orderHeadService.updateRoomCalendarInfo(orderNo, succeeded ? 3 : 2);
                                break;
                        }
                        break;
                }


                //更新优惠券
                switch (orderHead.getVipFlag()) {
                    //c2b
                    case 0:
                        if (null != orderHead.getUserCouponId()) {
                            UserCouponInfo userCouponInfo = userCouponInfoService.getById(orderHead.getUserCouponId());
                            UserCouponInfo userCouponInfoNew = new UserCouponInfo().setId(userCouponInfo.getId());
                            if (succeeded) {
                                userCouponInfoNew.setUsed(UserCouponInfoStatus.USE.value());
                            } else {
                                userCouponInfoNew.setUsed(UserCouponInfoStatus.NO_USE.value());
                            }
                            boolean b2 = userCouponInfoService.updateById(userCouponInfoNew);
                            if (!b2) {
                                throw new ServiceException("优惠券更新失败");
                            }
                        }
                        break;
                }


                //酒店房间信息
                long days = DateUtil.between(orderHead.getCheckIn(), orderHead.getCheckOut(), DateUnit.DAY);
//                //如果臻选订单则是钱包支付，需写入余额
//                if (OrderVipFlagEnum.getVipList().contains(orderHead.getVipFlag()) && !Objects.equals(cardType, 0)) {
//                    //钱包支付写入余额消息
//                    try {
//                        //查询酒店方手机号
//                        String hotelName = esHotelInfo.getName();
//                        String checkIn = DateUtils.toYYMMddStr(orderHead.getCheckIn());
//                        String checkOut = DateUtils.toYYMMddStr(orderHead.getCheckOut());
//                        UserMemberCard card = userMemberCardService.getUserMemberCard(orderHead.getUserId(), cardType);
//                        if (card != null) {
//                            Map<String, Object> param = Maps.newHashMap();
//                            param.put("hotelName", hotelName);
//                            param.put("checkIn", checkIn);
//                            param.put("checkOut", checkOut);
//                            param.put("count", days);
//                            param.put("amount", FormatUtils.fenToYuan(orderHead.getSnapshotTotalFee()));
//                            param.put("remainAmount", FormatUtils.fenToYuan(card.getRemainGiveAmount() + card.getRemainPayAmount()));
//                            Map<String, String> map = messageNoticeTemplateService.commonValue(param, MessageTemplate.CARD_ORDER);
//                            MemberCardDetail detail = new MemberCardDetail();
//                            detail.setUserId(orderHead.getUserId());
//                            detail.setContent(map.get("content"));
//                            detail.setIconUrl(map.get("iconUrl"));
//                            detail.setCreateTime(new Date());
//                            detail.setCardType(cardType);
//                            memberCardDetailService.insert(detail);
//                        }
//                    } catch (Exception e) {
//                        log.error("钱包支付，写入余额失败{}", e.getLocalizedMessage());
//                        e.printStackTrace();
//                    }
//                }


                switch (orderHead.getSourceType()) {
                    case HotelSourceType.YYKS:
                        //发送酒店通知
                        smsService.sendSmsToHotelForOrderComplete(
                                esHotelInfo.getPhone()
                                , null != orderHead.getContactName() ? orderHead.getContactName() : "佚名"
                                , DateUtils.toYYMMddStr(orderHead.getCheckIn())
                                , esHotelInfo.getName()
                                , esRoomInfo.getTitle()
                                , String.valueOf(orderHead.getRoomCount())
                                , String.valueOf(days)
                        );
                        break;
                }


                //给用户发送短信
                smsService.sendSmsToUserForOrderComplete(
                        (Objects.nonNull(userInfo) ? userInfo.getPhone() : orderHead.getContactPhone())
                        , null != orderHead.getContactName() ? orderHead.getContactName() : "佚名"
                        , DateUtils.toYYMMddStr(orderHead.getCheckIn())
                        , esHotelInfo.getName()
                        , esRoomInfo.getTitle()
                        , String.valueOf(orderHead.getRoomCount())
                        , String.valueOf(days)
                        , esHotelInfo.getAddress()
                        , esHotelInfo.getPhone()
                );


                //记录订单成功通知
                Map<String, String> messageNoticeTemplateMap = messageNoticeTemplateService.orderAfterHandleValue(MessageTemplate.ORDER_ACCEPT, esHotelInfo.getName(), DateUtils.toYYMMddStr(orderHead.getCheckIn()), DateUtils.toYYMMddStr(orderHead.getCheckOut()), orderHead.getRoomCount());
                messageNoticeService.createNoticeAndSave(messageNoticeTemplateMap, orderHead.getUserId(), esHotelInfo.getId());


                //个推推送
                String title = "您有新订单到了!";
                String content = orderHead.getOrderNo();
                Map<String, String> geTuiMap = new HashMap<>();
                geTuiMap.put("title", title);
                geTuiMap.put("content", content);
                geTuiService.singlePush(String.valueOf(orderHead.getUserId()), title, JSONObject.toJSONString(geTuiMap));
                //用户下单给后台发送一条mq
                Long grabTheOrderTimestamp = null;
                try {
                    grabTheOrderTimestamp = JSONUtil.parseObj(orderHead.getExtraInfo()).getLong(OrderHeadExtraInfoConstant.GRAB_THE_ORDER_TIMESTAMP);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                int type = 1;
                if (Objects.isNull(grabTheOrderTimestamp) || grabTheOrderTimestamp > System.currentTimeMillis()) {
                    type = 2;
                }
                mqProducerService.sendGrabTheOrderSuccessMsg(new GrabTheOrderSuccessMessage().setOrderNo(orderNo).setType(type));
            } catch (Exception e) {
                log.info("联合订单回调处理失败------------{}", orderHead.getOrderNo());
                e.printStackTrace();
            }
        }

    }

    //订单支付回调处理,事务包裹:v3.3
    @Transactional(rollbackFor = Exception.class)
    public void payCallBackTBefore(OrderHead orderHead, String orderNo, PayTypeEnum payTypeEnum, Boolean succeeded) {
        Integer cardType = VipCardTypeEnum.getCardTypeByOrderVipFlagValue(orderHead.getVipFlag());
        //判断是否是待支付订单
        if (OrderStatusEnum.PREPAY.value().equals(orderHead.getStatus())) {
            //更新房态信息
            boolean b1 = false;
            switch (orderHead.getVipFlag()) {
                //c2b 和 3.4订单
                case 0:
                    //v3.4 b2c
                case 2:
                    List<RoomCalendarInfo> roomCalendarInfos = roomCalendarInfoService.list(new QueryWrapper<RoomCalendarInfo>()
                            .eq(RoomCalendarInfo.ROOM_ID, orderHead.getRoomId())
                            .ge(RoomCalendarVipInfo.DATE, orderHead.getCheckIn())
                            .lt(RoomCalendarVipInfo.DATE, orderHead.getCheckOut()));
                    ArrayList<RoomCalendarInfo> roomCalendarInfoArrayList = new ArrayList<>();
                    for (RoomCalendarInfo roomCalendarInfo : roomCalendarInfos) {
                        if (roomCalendarInfo.getLockCount() < orderHead.getRoomCount()) {
                            throw new ServiceException("房态锁定房间不足");
                        }
                        RoomCalendarInfo roomCalendarInfoNew = new RoomCalendarInfo();
                        roomCalendarInfoNew.setId(roomCalendarInfo.getId());
                        roomCalendarInfoNew.setLockCount(roomCalendarInfo.getLockCount() - orderHead.getRoomCount());
                        if (!succeeded) {
                            roomCalendarInfoNew.setCount(roomCalendarInfo.getCount() + orderHead.getRoomCount());
                        }
                        roomCalendarInfoArrayList.add(roomCalendarInfoNew);
                    }
                    b1 = roomCalendarInfoService.updateBatchById(roomCalendarInfoArrayList);
                    break;
                //vip
                case 1:
                    List<RoomCalendarVipInfo> roomCalendarVipInfos = roomCalendarVipInfoService.list(new QueryWrapper<RoomCalendarVipInfo>()
                            .eq(RoomCalendarVipInfo.ROOM_ID, orderHead.getRoomId())
                            .ge(RoomCalendarVipInfo.DATE, orderHead.getCheckIn())
                            .lt(RoomCalendarVipInfo.DATE, orderHead.getCheckOut()));
                    ArrayList<RoomCalendarVipInfo> roomCalendarVipInfoArrayList = new ArrayList<>();
                    for (RoomCalendarVipInfo roomCalendarVipInfo : roomCalendarVipInfos) {
                        if (roomCalendarVipInfo.getLockCount() < orderHead.getRoomCount()) {
                            throw new ServiceException("房态锁定房间不足");
                        }
                        RoomCalendarVipInfo roomCalendarVipInfoNew = new RoomCalendarVipInfo();
                        roomCalendarVipInfoNew.setId(roomCalendarVipInfo.getId());
                        roomCalendarVipInfoNew.setLockCount(roomCalendarVipInfo.getLockCount() - orderHead.getRoomCount());
                        if (!succeeded) {
                            roomCalendarVipInfo.setCount(roomCalendarVipInfo.getCount() + orderHead.getRoomCount());
                        }
                        roomCalendarVipInfoArrayList.add(roomCalendarVipInfoNew);
                    }
                    b1 = roomCalendarVipInfoService.updateBatchById(roomCalendarVipInfoArrayList);
                    break;
                //jip
                case 3:
                    List<RoomCalendarJipInfo> roomCalendarJipInfos = roomCalendarJipInfoService.list(new QueryWrapper<RoomCalendarJipInfo>()
                            .eq(RoomCalendarJipInfo.ROOM_ID, orderHead.getRoomId())
                            .ge(RoomCalendarJipInfo.DATE, orderHead.getCheckIn())
                            .lt(RoomCalendarJipInfo.DATE, orderHead.getCheckOut()));
                    ArrayList<RoomCalendarJipInfo> roomCalendarJipInfoArrayList = new ArrayList<>();
                    for (RoomCalendarJipInfo roomCalendarJipInfo : roomCalendarJipInfos) {
                        if (roomCalendarJipInfo.getLockCount() < orderHead.getRoomCount()) {
                            throw new ServiceException("房态锁定房间不足");
                        }
                        RoomCalendarJipInfo roomCalendarJipInfoNew = new RoomCalendarJipInfo();
                        roomCalendarJipInfoNew.setId(roomCalendarJipInfo.getId());
                        roomCalendarJipInfoNew.setLockCount(roomCalendarJipInfo.getLockCount() - orderHead.getRoomCount());
                        if (!succeeded) {
                            roomCalendarJipInfo.setCount(roomCalendarJipInfo.getCount() + orderHead.getRoomCount());
                        }
                        roomCalendarJipInfoArrayList.add(roomCalendarJipInfoNew);
                    }
                    b1 = roomCalendarJipInfoService.updateBatchById(roomCalendarJipInfoArrayList);
                    break;
                default:
                    throw new ServiceException("订单类型错误");
            }
            if (!b1) {
                throw new ServiceException("房态更新失败");
            }
            //更新优惠券
            switch (orderHead.getVipFlag()) {
                //c2b
                case 0:
                    //v3.4 b2c
                case 2:
                    if (null != orderHead.getUserCouponId()) {
                        UserCouponInfo userCouponInfo = userCouponInfoService.getById(orderHead.getUserCouponId());
                        UserCouponInfo userCouponInfoNew = new UserCouponInfo().setId(userCouponInfo.getId());
                        if (succeeded) {
                            userCouponInfoNew.setUsed(UserCouponInfoStatus.USE.value());
                        } else {
                            userCouponInfoNew.setUsed(UserCouponInfoStatus.NO_USE.value());
                        }
                        boolean b2 = userCouponInfoService.updateById(userCouponInfoNew);
                        if (!b2) {
                            throw new ServiceException("优惠券更新失败");
                        }
                    }
                    break;
                //vip
                case 1:
                    //jip
                case 3:
                    break;
                default:
                    throw new ServiceException("订单类型错误");
            }
            //酒店房间信息
            HotelInfo hotelInfo = hotelInfoService.getById(orderHead.getHotelId());
            RoomInfo roomInfo = roomInfoService.getById(orderHead.getRoomId());
            long days = DateUtil.between(orderHead.getCheckIn(), orderHead.getCheckOut(), DateUnit.DAY);
            //如果臻选订单则是钱包支付，需写入余额
            if (OrderVipFlagEnum.getVipList().contains(orderHead.getVipFlag()) && !Objects.equals(cardType, 0)) {
                //钱包支付写入余额消息
                try {
                    //查询酒店方手机号
                    String hotelName = hotelInfo.getName();
                    String checkIn = DateUtils.toYYMMddStr(orderHead.getCheckIn());
                    String checkOut = DateUtils.toYYMMddStr(orderHead.getCheckOut());
                    UserMemberCard card = userMemberCardService.getUserMemberCard(orderHead.getUserId(), cardType);
                    if (card != null) {
                        Map<String, Object> param = Maps.newHashMap();
                        param.put("hotelName", hotelName);
                        param.put("checkIn", checkIn);
                        param.put("checkOut", checkOut);
                        param.put("count", days);
                        param.put("amount", FormatUtils.fenToYuan(orderHead.getSnapshotTotalFee()));
                        param.put("remainAmount", FormatUtils.fenToYuan(card.getRemainGiveAmount() + card.getRemainPayAmount()));
                        Map<String, String> map = messageNoticeTemplateService.commonValue(param, MessageTemplate.CARD_ORDER);
                        MemberCardDetail detail = new MemberCardDetail();
                        detail.setUserId(orderHead.getUserId());
                        detail.setContent(map.get("content"));
                        detail.setIconUrl(map.get("iconUrl"));
                        detail.setCreateTime(new Date());
                        detail.setCardType(cardType);
                        memberCardDetailService.insert(detail);
                    }
                } catch (Exception e) {
                    log.error("钱包支付，写入余额失败{}", e.getLocalizedMessage());
                    e.printStackTrace();
                }
            }
            //更新订单信息
            OrderHead orderHeadNew = new OrderHead();
            orderHeadNew.setId(orderHead.getId());
            orderHeadNew.setGmtModified(new Date());
            if (succeeded) {
                //住店那天18点后的订单直接改为入住中
                if (new Date().after(DateUtil.beginOfDay(orderHead.getCheckIn()).offset(DateField.HOUR, 18))) {
                    orderHeadNew.setStatus(OrderStatusEnum.LIVING.value());
                } else {
                    orderHeadNew.setStatus(OrderStatusEnum.PRECHECKIN.value());
                }
            } else {
                orderHeadNew.setStatus(OrderStatusEnum.PAYFAILED.value());
            }
            orderHeadNew.setPaymentMethod(payTypeEnum.value());
            boolean b = orderHeadService.updateById(orderHeadNew);
            if (!b) {
                throw new ServiceException("订单更新失败");
            }
            //发送酒店通知
            smsService.sendSmsToHotelForOrderComplete(
                    hotelInfo.getPhone()
                    , null != orderHead.getContactName() ? orderHead.getContactName() : "佚名"
                    , DateUtils.toYYMMddStr(orderHead.getCheckIn())
                    , hotelInfo.getName()
                    , roomInfo.getTitle()
                    , String.valueOf(orderHead.getRoomCount())
                    , String.valueOf(days)
            );
            //给用户发送短信
            UserInfo userInfo = userInfoService.getById(orderHead.getUserId());
            switch (orderHead.getVipFlag()) {
                case 3:
                    Map<String, String> map = new HashMap<>();
                    map.put("phone", userInfo.getPhone());
                    smsService.sendSmsToBoolean(map, "SMS_181867398");
                    break;
                default:
                    smsService.sendSmsToUserForOrderComplete(
                            (Objects.nonNull(userInfo) ? userInfo.getPhone() : orderHead.getContactPhone())
                            , null != orderHead.getContactName() ? orderHead.getContactName() : "佚名"
                            , DateUtils.toYYMMddStr(orderHead.getCheckIn())
                            , hotelInfo.getName()
                            , roomInfo.getTitle()
                            , String.valueOf(orderHead.getRoomCount())
                            , String.valueOf(days)
                            , hotelInfo.getAddress()
                            , hotelInfo.getPhone()
                    );
                    break;
            }
            //记录订单成功通知
            Map<String, String> messageNoticeTemplateMap = messageNoticeTemplateService.orderAfterHandleValue(MessageTemplate.ORDER_ACCEPT, hotelInfo.getName(), DateUtils.toYYMMddStr(orderHead.getCheckIn()), DateUtils.toYYMMddStr(orderHead.getCheckOut()), orderHead.getRoomCount());
            messageNoticeService.createNoticeAndSave(messageNoticeTemplateMap, orderHead.getUserId(), hotelInfo.getId());
            //个推推送
            String title = "您有新订单到了!";
            String content = orderHead.getOrderNo();
            Map<String, String> geTuiMap = new HashMap<>();
            geTuiMap.put("title", title);
            geTuiMap.put("content", content);
            geTuiService.singlePush(String.valueOf(orderHead.getUserId()), title, JSONObject.toJSONString(geTuiMap));
            //用户下单给后台发送一条mq
            Long grabTheOrderTimestamp = null;
            try {
                grabTheOrderTimestamp = JSONUtil.parseObj(orderHead.getExtraInfo()).getLong(OrderHeadExtraInfoConstant.GRAB_THE_ORDER_TIMESTAMP);
            } catch (Exception e) {
                e.printStackTrace();
            }
            int type = 1;
            if (Objects.isNull(grabTheOrderTimestamp) || grabTheOrderTimestamp > System.currentTimeMillis()) {
                type = 2;
            }
            mqProducerService.sendGrabTheOrderSuccessMsg(new GrabTheOrderSuccessMessage().setOrderNo(orderNo).setType(type));
        }
    }

}
